//
//  SPPreferencePane.m
//  snomPhone
//
//  Created by Daniel Hazelbaker on 11/5/08.
//  Copyright 2008 Blue Box Moon. All rights reserved.
//

#import "SPPreferencePane.h"
#import "BMPreferences.h"
#import "BMPluginController.h"
#import "BMSnomPhone.h"
#import "preferences.h"
#import "comBlueboxmoonPhoneABLookup.h"
#import "comBlueboxmoonPhoneWebABLookup.h"
#import "comBlueboxmoonPhoneiTunes.h"
#import "comBlueboxmoonPhoneWebAddress.h"
#import "comBlueboxmoonPhoneHover.h"


@implementation SPPreferencePane


//
// Initialize the preference pane.
//
- (id)initWithBundle:(NSBundle *)bundle
{
    if ([super initWithBundle:bundle] == nil)
        return nil;
    
    [comBlueboxmoonPhoneABLookup setDefaultPreferences];
    [comBlueboxmoonPhoneWebABLookup setDefaultPreferences];
    [comBlueboxmoonPhoneiTunes setDefaultPreferences];
    [comBlueboxmoonPhoneWebAddress setDefaultPreferences];
    [comBlueboxmoonPhoneHover setDefaultPreferences];
    
    [self upgradeFromSnomPhone];
    
    return self;
}


//
// The view has loaded, read our preferences.
//
- (void)mainViewDidLoad
{
    NSAppleEventDescriptor  *returnObject;
    NSAppleScript	    *scriptObject;
    NSDictionary	    *error = nil;
    BMPreferences           *prefs;
    int			    i;

    
    //
    // Auto update the address-book plugin if it is installed.
    //
    [self updateAddressBookPlugin];
    
    //
    // Set initial values.
    //
    prefs = [BMSnomPhone preferences];
    if ([prefs valueForKey:kCountryCode] == nil)
        [prefs setValue:[[NSLocale autoupdatingCurrentLocale] objectForKey:NSLocaleCountryCode] forKeyPath:kCountryCode];
    [self setValue:prefs forKey:@"preferences"];
    
    //
    // Detect initial settings.
    //
    [self willChangeValueForKey:@"clickToDial"];
    clickToDial = [NSNumber numberWithBool:[[NSFileManager defaultManager] fileExistsAtPath:[[NSString stringWithFormat:@"~/Library/Address Book Plug-Ins/MacSnomeDial.bundle"] stringByExpandingTildeInPath]]];
    [self didChangeValueForKey:@"clickToDial"];
    
    //
    // Determine if we are a login item.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:@"tell application \"System Events\"\n"
                                                          "    return (name of every login item)\n"
                                                          "end tell\n"]];
    returnObject = [scriptObject executeAndReturnError:&error];
    for (i = 1; i <= [returnObject numberOfItems]; i++) {
        if ([[[returnObject descriptorAtIndex:i] stringValue] isEqual:@"MacSnomeStatus"] == YES) {
            [self willChangeValueForKey:@"runAtLogin"];
            runAtLogin = [NSNumber numberWithBool:YES];
            [self didChangeValueForKey:@"runAtLogin"];
            
            break;
        }
    }
    [scriptObject release];
    
    //
    // Check for forced MCX values.
    //
    if ([preferences valueIsForcedForKey:PREFERENCE_IPADDRESS])
        [tfIpAddress setEnabled:NO];
    if ([preferences valueIsForcedForKey:kWebAddressWebAddressKey])
        [tfWebAddressUrl setEnabled:NO];
    if ([preferences valueIsForcedForKey:kWebABURLKey])
        [tfExternalAddressBookUrl setEnabled:NO];
    if ([preferences valueIsForcedForKey:kWebABEnabledKey])
        [btExternalAddressBookEnabled setEnabled:NO];
    if ([preferences valueIsForcedForKey:kAddressBookEnableLookupKey])
        [btAddressBookEnabled setEnabled:NO];
    if ([preferences valueIsForcedForKey:kCountryCode])
        [tfCountryCode setEnabled:NO];
    
    //
    // Update the application status.
    //
    [self updateApplicationStatus];
}


//
// Save the preferences if they need to be saved.
//
- (void)willUnselect
{
}


//
// Set wether or not the run the phone status in the menu bar at login.
//
- (void)setRunAtLogin:(NSNumber *)status
{
    NSAppleScript   *scriptObject;
    NSDictionary    *error = nil;
    NSString	    *statusPath;
    
    
    //
    // Save the status.
    //
    [runAtLogin autorelease];
    runAtLogin = [status retain];
    
    //
    // Set the statusPath.
    //
    statusPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeStatus" ofType:@"app"];
    
    if ([status boolValue] == YES) {
        //
        // Turn on phone status.
        //
        [preferences synchronize];
        [[NSWorkspace sharedWorkspace] launchApplication:statusPath];
        
        //
        // Make it a login item.
        //
        scriptObject = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:@"tell application \"System Events\"\n"
                                                              "    if \"%@\" is not in (path of every login item) then\n"
                                                              "        make login item at end with properties {hidden: false, path:\"%@\"}\n"
                                                              "    end if\n"
                                                              "end tell\n", statusPath, statusPath]];
        [scriptObject executeAndReturnError:&error];
        [scriptObject release];
    }
    else {
        //
        // Turn off phone status.
        //
        scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"MacSnomeStatus\" to quit"];
        [scriptObject executeAndReturnError:&error];
        [scriptObject release];
        
        //
        // Remove it as a login item.
        //
        scriptObject = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:@"tell application \"System Events\"\n"
                                                              "    delete (every login item whose name is \"MacSnomeStatus\")\n"
                                                              "end tell\n"]];
        [scriptObject executeAndReturnError:&error];
        [scriptObject release];
    }
    
    [NSThread sleepForTimeInterval:0.5];
    [self updateApplicationStatus];
}


//
// Automatically update the address book plug-in if versions don't match.
//
- (void)updateAddressBookPlugin
{
    NSString	*path;
    
    
    path = [[NSString stringWithFormat:@"~/Library/Address Book Plug-Ins/MacSnomeDial.bundle"] stringByExpandingTildeInPath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:path] == YES) {
        NSString *installedVersion, *availableVersion;
        NSBundle *bundle;
        
        bundle = [NSBundle bundleWithPath:path];
        installedVersion = [[bundle infoDictionary] valueForKey:@"CFBundleVersion"];
        bundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeDial" ofType:@"bundle"]];
        availableVersion = [[bundle infoDictionary] valueForKey:@"CFBundleVersion"];
        if ([installedVersion isEqualToString:availableVersion] != YES) {
            [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
            [[NSFileManager defaultManager] copyItemAtPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeDial" ofType:@"bundle"] toPath:path error:NULL];
        }
    }
}


//
// Set wether or not the Address Book plugin is installed.
//
- (void)setClickToDial:(NSNumber *)value
{
    NSString	*path;
    
    
    //
    // Save the value.
    //
    [clickToDial autorelease];
    clickToDial = [value retain];
    
    path = [[NSString stringWithFormat:@"~/Library/Address Book Plug-Ins/MacSnomeDial.bundle"] stringByExpandingTildeInPath];
    
    if ([value boolValue] == YES) {
        //
        // Copy the plug-in in place if it does not already exist.
        //
        [preferences synchronize];
        if ([[NSFileManager defaultManager] fileExistsAtPath:path] == NO)
            [[NSFileManager defaultManager] copyItemAtPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeDial" ofType:@"bundle"] toPath:path error:NULL];
    }
    else {
        //
        // Remove the plug-in.
        //
        [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
    }
}


//
// Set a preference value.
//
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath
{
    if ([keyPath rangeOfString:@"preferences."].location == NSNotFound)
        [super setValue:value forKeyPath:keyPath];
    else
    {
        [self willChangeValueForKey:@"preferences"];
        [preferences setValue:value forKeyPath:[keyPath substringFromIndex:12]];
        [preferences synchronize];
        [self didChangeValueForKey:@"preferences"];
    }
}


//
// Retrieve a preference value.
//
- (id)valueForKeyPath:(NSString *)keyPath
{
    if ([keyPath rangeOfString:@"preferences."].location == NSNotFound)
        return [super valueForKeyPath:keyPath];
    
    return [preferences valueForKeyPath:[keyPath substringFromIndex:12]];
}


//
// Update the state of the application running status.
//
- (void)updateApplicationStatus
{
    if ([self applicationIsRunning])
    {
        [tfMenuStatus setStringValue:@"Phone application is currently running."];
        [startStopButton setTitle:@"Stop"];
    }
    else
    {
        [tfMenuStatus setStringValue:@"Phone application is not running."];
        [startStopButton setTitle:@"Start"];
    }
}


//
// Determine if the application is currently running.
//
- (BOOL)applicationIsRunning
{
    ProcessSerialNumber psn = { 0, kNoProcess };
    CFStringRef		stringRef;
    BOOL		application = NO;
    
    
    //
    // Walk the entire process tree.
    //
    while (!GetNextProcess(&psn)) {
        if (psn.lowLongOfPSN == kNoProcess)
            break;
        
        CopyProcessName(&psn, &stringRef);
        if ([(NSString *)stringRef isEqual:@"MacSnomeStatus"] == YES) {
            application = YES;
            CFRelease(stringRef);
            break;
        }
        CFRelease(stringRef);
    }
    
    return application;
}


//
// Start or stop the phone status.
//
- (IBAction)btnStartStopApplication:(NSButton *)sender
{
    if ([[sender title] isEqual:@"Start"])
    {
        NSString    *statusPath;
        
        statusPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeStatus" ofType:@"app"];
        [[NSWorkspace sharedWorkspace] launchApplication:statusPath];
    }
    else
    {
        [self killApplication];
    }
    
    //
    // Wait 2 seconds and then update application status.
    //
    [NSThread sleepForTimeInterval:2];
    [self updateApplicationStatus];
}


//
// Determine if the application is currently running.
//
- (void)killApplication
{
    ProcessSerialNumber psn = { 0, kNoProcess };
    CFStringRef		stringRef;
    
    
    //
    // Walk the entire process tree.
    //
    while (!GetNextProcess(&psn)) {
        if (psn.lowLongOfPSN == kNoProcess)
            break;
        
        CopyProcessName(&psn, &stringRef);
        if ([(NSString *)stringRef isEqual:@"MacSnomeStatus"] == YES) {
            KillProcess(&psn);
            break;
        }
        CFRelease(stringRef);
    }
}


//
// Perform an automatic upgrade from the old system. Basically remove old files and
// install new ones.
//
- (void)upgradeFromSnomPhone
{
    NSAppleEventDescriptor  *returnObject;
    ProcessSerialNumber     psn = { 0, kNoProcess };
    NSAppleScript           *scriptObject;
    NSDictionary            *scriptError = nil;
    CFStringRef             stringRef;
    NSString                *path;
    int                     i;
    
    
    //
    // Check if the Address Book plug-in needs to be replaced.
    //
    path = [[NSString stringWithFormat:@"~/Library/Address Book Plug-Ins/snomDial.bundle"] stringByExpandingTildeInPath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:path] == YES) {
        [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
        path = [[NSString stringWithFormat:@"~/Library/Address Book Plug-Ins/MacSnomeDial.bundle"] stringByExpandingTildeInPath];
        [[NSFileManager defaultManager] copyItemAtPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeDial" ofType:@"bundle"] toPath:path error:NULL];
    }
    
    //
    // Check if the old application is running.
    //
    while (!GetNextProcess(&psn)) {
        if (psn.lowLongOfPSN == kNoProcess)
            break;
        
        CopyProcessName(&psn, &stringRef);
        if ([(NSString *)stringRef isEqual:@"snomStatus"] == YES) {
            CFRelease(stringRef);
            
            //
            // Kill the old process and launch the new one.
            //
            KillProcess(&psn);
            path = [[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeStatus" ofType:@"app"];
            [[NSWorkspace sharedWorkspace] launchApplication:path];
            
            break;
        }
        CFRelease(stringRef);
    }
    
    //
    // Remove the old preference pane.
    //
    path = [[NSString stringWithFormat:@"~/Library/PreferencePanes/snomPhone.prefPane"] stringByExpandingTildeInPath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:path] == YES)
        [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
    path = [[NSString stringWithFormat:@"/Library/PreferencePanes/snomPhone.prefPane"] stringByExpandingTildeInPath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:path] == YES)
        [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
    
    //
    // Check if the old status app was set to auto start.
    //
    scriptObject = [[[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:@"tell application \"System Events\"\n"
                                                           "    return (name of every login item)\n"
                                                           "end tell\n"]] autorelease];
    returnObject = [scriptObject executeAndReturnError:&scriptError];
    for (i = 1; i <= [returnObject numberOfItems]; i++) {
        if ([[[returnObject descriptorAtIndex:i] stringValue] isEqual:@"snomStatus"] == YES) {
            //
            // Remove the old login item.
            //
            scriptObject = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:@"tell application \"System Events\"\n"
                                                                  "    delete (every login item whose name is \"snomStatus\")\n"
                                                                  "end tell\n"]];
            [scriptObject executeAndReturnError:&scriptError];
            [scriptObject release];
            
            //
            // Make it a login item.
            //
            path = [[NSBundle bundleForClass:[self class]] pathForResource:@"MacSnomeStatus" ofType:@"app"];
            scriptObject = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:@"tell application \"System Events\"\n"
                                                                  "    if \"%@\" is not in (path of every login item) then\n"
                                                                  "        make login item at end with properties {hidden: false, path:\"%@\"}\n"
                                                                  "    end if\n"
                                                                  "end tell\n", path, path]];
            [scriptObject executeAndReturnError:&scriptError];
            [scriptObject release];
            
            break;
        }
    }
}


@end
